package nba2kmodtool.filedesc;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import nba2kmodtool.util.ByteFileReader;
import nba2kmodtool.util.PluginDDS;

/**
 * NBA2K Game Texture Exporter
 * @company ZSword (C) Copyright
 * @author JemiZhuu(周士淳)
 * @category N2kTextureExporter
 * @version 1.0
 * @since 2011-11-16
 */
public class N2kTextureExporter {
	private static final boolean IS_DEBUG = BaseIffFile.IS_DEBUG;

	protected BaseIffFile iff;
	protected long fileType;
	protected File file;
	protected File cdfFile;

	protected N2kTextureExporter(BaseIffFile iff) {
		this.iff = iff;
		this.fileType = iff.fileType;
		this.file = iff.file;
		this.cdfFile = iff.cdfFile;
	}

	/**
	 * Export Texture data to File
	 * @param outfile
	 * @param target
	 * @throws IOException
	 */
	public void exportTextureFile(File outfile, N2kTextureFile target) throws IOException {
		ByteFileReader in = null;
		if (fileType == 0xFF3BEF94L) {
			in = new ByteFileReader(file, "r");

		} else if (fileType == 0xF0985030L) {
			in = new ByteFileReader(cdfFile, "r");
		}
		ByteFileReader out = new ByteFileReader(outfile, "rw");
		if ("BMP".equals(target.getPixelFormat())) {
			this.writeBMPTexture(out, in, target);
		} else {
			this.writeDDSTexture(out, in, target);
		}
		in.close();
		out.close();
	}

	/**
	 * Write Texture data to BMP File
	 * @param out
	 * @param in
	 * @param target
	 * @throws IOException
	 */
	private void writeBMPTexture(ByteFileReader out, ByteFileReader in, N2kTextureFile target) throws IOException {
		//write BMP header
		int bmpSize = target.width * target.height * 4 + 0x36 + 0x02;
		int dataSize = bmpSize - 0x36;
		out.write("BM".getBytes(), 0, 2);
		out.writeInt(Integer.reverseBytes(bmpSize));
		out.writeInt(0x00000000);
		out.writeInt(0x36000000);
		out.writeInt(0x28000000);
		out.writeInt(Integer.reverseBytes(target.width));
		out.writeInt(Integer.reverseBytes(target.height));
		out.writeInt(0x01002000);
		out.writeInt(0x00000000);
		out.writeInt(Integer.reverseBytes(bmpSize - 0x36));
		out.writeInt(0x120B0000);
		out.writeInt(0x120B0000);
		out.writeInt(0x00000000);
		out.writeInt(0x00000000);
		if (target.indexType <= 0) {
			//write data
			ByteBuffer tb = ByteBuffer.allocate(dataSize);
			in.seek(target.dataStart);
			in.read(tb.array());
			IntBuffer buffer = tb.asIntBuffer();
			for (int i = 0; i < target.width * target.height; i++) {
				buffer.position(buffer.capacity() - i - 1);
				out.writeInt(buffer.get());
			}
		} else {
			IffBlockIndex index = target.index;
			int count = index.getIndexCount();
			long totalSize = 0;
			for (int i = 0; i < count; i++) {
				totalSize += index.getSize(i);
			}
			ByteBuffer buff = ByteBuffer.allocate((int) totalSize);
			int witeCount = 0;
			for (int i = count - 1; i >= 0; i--) {
				long addr = index.getAddr(i);
				long size = index.getSize(i);
				in.seek(addr);
				if (IS_DEBUG) {
					System.out.printf("BMP: data-%X-%X\n", addr, size);
				}
				in.read(buff.array(), witeCount, (int) size);
				witeCount += size;
			}
			out.write(buff.array());
		}
		out.setLength(out.getFilePointer());
	}

	/**
	 * Write Texture data to DDS File
	 * @param out
	 * @param in
	 * @param target
	 * @throws IOException
	 */
	private void writeDDSTexture(ByteFileReader out, ByteFileReader in, N2kTextureFile target) throws IOException {
		PluginDDS.writeHeader(out, target.pixelFormat, target.width, target.height, target.mip);
		if (target.indexType <= 0) {
			ByteBuffer buff = ByteBuffer.allocate((int) target.dataSize);
			in.seek(target.dataStart);
			in.read(buff.array());
			out.write(buff.array());
		} else {
			IffBlockIndex index = target.index;
			int count = index.getIndexCount();
			long totalSize = 0;
			for (int i = 0; i < count; i++) {
				totalSize += index.getSize(i);
			}
			ByteBuffer buff = ByteBuffer.allocate((int) totalSize);
			int witeCount = 0;
			for (int i = count - 1; i >= 0; i--) {
				long addr = index.getAddr(i);
				long size = index.getSize(i);
				in.seek(addr);
				if (IS_DEBUG) {
					System.out.printf("DDS: data-%X-%X\n", addr, size);
				}
				in.read(buff.array(), witeCount, (int) size);
				witeCount += size;
			}
			out.write(buff.array());
		}
		out.setLength(out.getFilePointer());
	}

}
